module ysyx_22040213_ALU(
	input [63:0] data1,
	input [63:0] data2,
	input [16:0] alu_op,
	input clk,
	input rst,
	input MEM_allow_in,
	output alu_busy,
	output reg [63:0] wdata
);
/*verilator lint_off UNUSED*/

wire signed [63:0] sdata1;
wire signed [63:0] sdata2;
assign sdata1 = data1;
assign sdata2 = data2;

reg div_doing;
wire div_valid;
wire flush = 1'b0;
wire [1:0] div_signed;
wire div_ready;
wire div_out_valid;
wire [63:0] quotient;
wire [63:0] remainder;

reg mul_doing;
wire mul_valid;
wire [1:0] mul_signed;
wire mul_ready;
wire mul_out_valid;
wire [63:0] result_hi;
wire [63:0] result_lo;

assign alu_busy = |alu_op[16:13] && !div_out_valid && !div_buffer_valid || alu_op[12] && !mul_out_valid && !mul_buffer_valid;
assign div_valid  = |alu_op[16:13] && !div_doing && !div_out_valid;
assign div_signed  = |alu_op[14:13] ? 2'b11 : 2'b00;

assign mul_valid  =  alu_op[12]    && !mul_doing && !mul_out_valid;
assign mul_signed = 2'b00;

reg div_buffer_valid;
reg mul_buffer_valid;
reg [63:0] mul_buffer_result_lo;
reg [63:0] div_buffer_quotient;
reg [63:0] div_buffer_remainder;

always @(posedge clk)begin
  if(rst)begin
    div_doing <= 1'b0;
    mul_doing <= 1'b0;
  end else if(mul_out_valid) begin
    mul_doing <= 1'b0;
  end else if(div_out_valid) begin
    div_doing <= 1'b0;
  end else if(div_valid && div_ready)begin
    div_doing <= 1'b1;
  end else if(mul_valid && mul_ready)begin
    mul_doing <= 1'b1;
  end
  
  if(~MEM_allow_in && mul_out_valid)begin
    mul_buffer_valid <= 1'b1;
    mul_buffer_result_lo <= result_lo;
  end else if(MEM_allow_in) begin
    mul_buffer_valid <= 1'b0;
  end
  if(~MEM_allow_in && div_out_valid)begin
    div_buffer_valid <= 1'b1;
    div_buffer_quotient <= quotient;
    div_buffer_remainder <= remainder;
  end else if(MEM_allow_in)begin
    div_buffer_valid <= 1'b0;
  end

end
	wire [63:0] o_result_lo = mul_buffer_valid ? mul_buffer_result_lo : result_lo;
	wire [63:0] o_quotient  = div_buffer_valid ? div_buffer_quotient : quotient;
	wire [63:0] o_remainder = div_buffer_valid ? div_buffer_remainder : remainder;

 	MuxKey #(17, 17, 64) i0 (wdata, alu_op, {
		17'b00000000000000001, data1+data2,
		17'b00000000000000010, data1-data2,
		17'b00000000000000100, (sdata1 < sdata2) ? 64'h00000001 : 64'h0,//slt 2	
		17'b00000000000001000, (data1  < data2 ) ? 64'h00000001 : 64'h0,//sltiu 3
		17'b00000000000010000, data1 & data2,//and 4
		17'b00000000000100000, ~(data1 | data2),//nor 5	
		17'b00000000001000000, data1 | data2,//or 6
		17'b00000000010000000, data1 ^ data2,//xor 7
		17'b00000000100000000, data1 << data2[5:0],//sll sllw differenti 8
		17'b00000001000000000, data1 >> data2[5:0],//srl 9 
		17'b00000010000000000, data1 >>> data2[5:0],//sra 10  arithmetic shift right
		17'b00000100000000000, data2,//lui 11
		17'b00001000000000000, o_result_lo,//data1 * data2,//mul 12	
		17'b00010000000000000, o_quotient,//sdata1 / sdata2,//div 13
		17'b00100000000000000, o_remainder,//sdata1 % sdata2,//rem 14
		17'b01000000000000000, o_remainder,//data1 % data2, //remu 15
		17'b10000000000000000, o_quotient//data1 / data2  //divu 16
		});


	ysyx_22040213_mul mul1(
	  .clk(clk),
	  .rst(rst),
	  .mul_valid(mul_valid),
	  .flush(flush),
	  .mul_signed(mul_signed),
	  .multiplicand(data1),
	  .multiplier(data2),
	  .mul_ready(mul_ready),
	  .out_valid(mul_out_valid),
	  .result_hi(result_hi),
	  .result_lo(result_lo)
	);

	ysyx_22040213_div div1(
	  .clk(clk),
	  .rst(rst),
	  .div_valid(div_valid),
	  .flush(flush),
	  .div_signed(div_signed),
	  .dividend(data1),
	  .divisor(data2),
	  .div_ready(div_ready),
	  .out_valid(div_out_valid),
	  .quotient(quotient),
	  .remainder(remainder)
	);

endmodule



